package base.util;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

@SuppressWarnings("deprecation")
public class HttpRequestUtils {

	private static Logger logger = Logger.getLogger(HttpRequestUtils.class);

	private static PoolingHttpClientConnectionManager connMgr;

	private static RequestConfig requestConfig;

	private static final int MAX_TIMEOUT = 5000;

	static {

		// 设置连接池
		connMgr = new PoolingHttpClientConnectionManager();

		// 设置连接池大小
		connMgr.setMaxTotal(50);

		connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());

		RequestConfig.Builder configBuilder = RequestConfig.custom();

		// 设置连接超时
		configBuilder.setConnectTimeout(MAX_TIMEOUT);

		// 设置读取超时
		configBuilder.setSocketTimeout(MAX_TIMEOUT);

		// 设置从连接池获取连接实例的超时
		configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);

		// 在提交请求之前 测试连接是否可用
		// connMgr.setValidateAfterInactivity(1000);

		requestConfig = configBuilder.build();
	}

	/**
	 * httpPost
	 * 
	 * @param url
	 *            路径
	 * @param jsonParam
	 *            参数
	 * @return
	 */
	public static JSONObject httpPost(String url, JSONObject jsonParam) {
		return httpPost(url, jsonParam, false);
	}

	/**
	 * post请求
	 * 
	 * @param url
	 *            url地址
	 * @param jsonParam
	 *            参数
	 * @param noNeedResponse
	 *            不需要返回结果
	 * @return
	 */
	public static JSONObject httpPost(String url, JSONObject jsonParam, boolean noNeedResponse) {
		// post请求返回结果
		// DefaultHttpClient httpClient = new DefaultHttpClient();
		CloseableHttpClient httpClient = HttpClients.createDefault();
		JSONObject jsonResult = null;
		HttpPost method = new HttpPost(url);
		try {
			if (null != jsonParam) {
				// 解决中文乱码问题
				StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8");
				entity.setContentEncoding("UTF-8");
				entity.setContentType("application/json");
				method.setEntity(entity);
			}
			HttpResponse result = httpClient.execute(method);
			url = URLDecoder.decode(url, "UTF-8");
			/** 请求发送成功，并得到响应 **/
			if (result.getStatusLine().getStatusCode() == 200) {
				String str = "";
				try {
					/** 读取服务器返回过来的json字符串数据 **/
					str = EntityUtils.toString(result.getEntity(), "UTF-8");
					if (noNeedResponse) {
						return null;
					}
					/** 把json字符串转换成json对象 **/
					jsonResult = JSON.parseObject(str);
				} catch (Exception e) {
					logger.error("post请求提交失败:" + url, e);
				}
			}
		} catch (IOException e) {
			logger.error("post请求提交失败:" + url, e);
		}
		return jsonResult;
	}

	/**
	 * 发送 SSL POST 请求（HTTPS）
	 * 
	 * @param apiUrl
	 *            API接口URL
	 * @param entity
	 *            参数对象
	 * @param mimeType
	 * @return
	 */
	public static String doPostSSL(String apiUrl, String entity, String mimeType) {

		long startTime = System.currentTimeMillis();

		CloseableHttpResponse response = null;

		try {
			CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory())
					.setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
			HttpPost httpPost = new HttpPost(apiUrl);
			httpPost.setConfig(requestConfig);
			StringEntity stringEntity = new StringEntity(entity, ContentType.create(mimeType, Consts.UTF_8));
			httpPost.setEntity(stringEntity);
			response = httpClient.execute(httpPost);
			String resultStatus = null, resultString = null;
			if (response != null) {
				resultStatus = response.getStatusLine() != null ? response.getStatusLine().toString() : null;
				HttpEntity resEntity = response.getEntity();
				if (resEntity != null) {
					resultString = EntityUtils.toString(resEntity, Charset.forName("utf-8"));
				}
			}

			logger.info("url=" + apiUrl + " ,params=" + entity + ",resp=" + resultStatus + "\t" + resultString
					+ " ,usedTime=" + (System.currentTimeMillis() - startTime));

			return resultString;

		} catch (Exception e) {
			logger.error("doPost exception", e);
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					logger.error("doPost httpClient.close exception", e);
				}
			}
		}

		return null;
	}

	/**
	 * 发送 SSL 请求（HTTPS）
	 * 
	 * @param apiUrl
	 *            API接口URL
	 * @param entity
	 *            参数对象
	 * @param mimeType
	 * @return
	 */
	public static String doGetSSL(String apiUrl) {

		long startTime = System.currentTimeMillis();

		CloseableHttpResponse response = null;

		try {
			CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory())
					.setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();

			HttpGet httpMethod = new HttpGet(apiUrl);
			httpMethod.setConfig(requestConfig);
			response = httpClient.execute(httpMethod);

			String resultStatus = null, resultString = null;
			if (response != null) {
				resultStatus = response.getStatusLine() != null ? response.getStatusLine().toString() : null;
				HttpEntity resEntity = response.getEntity();
				if (resEntity != null) {
					resultString = EntityUtils.toString(resEntity, Charset.forName("utf-8"));
				}
			}

			logger.info("url=" + apiUrl + ",resp=" + resultStatus + "\t" + resultString + " ,usedTime="
					+ (System.currentTimeMillis() - startTime));

			return resultString;

		} catch (Exception e) {
			logger.error("doPost exception", e);
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					logger.error("doPost httpClient.close exception", e);
				}
			}
		}

		return null;
	}

	/**
	 * 发送get请求
	 * 
	 * @param url
	 *            路径
	 * @return
	 */
	public static JSONObject httpGet(String url) {
		// get请求返回结果
		JSONObject jsonResult = null;
		CloseableHttpClient httpClient = HttpClients.createDefault();
		try {
			// DefaultHttpClient client = new DefaultHttpClient();
			// 发送get请求
			HttpGet request = new HttpGet(url);
			HttpResponse response = httpClient.execute(request);
			/** 请求发送成功，并得到响应 **/
			if (response.getStatusLine().getStatusCode() == 200) {
				/** 读取服务器返回过来的json字符串数据 **/
				String strResult = EntityUtils.toString(response.getEntity(), "UTF-8");
				System.out.println(strResult);
				/** 把json字符串转换成json对象 **/
				jsonResult = JSON.parseObject(strResult);
				url = URLDecoder.decode(url, "UTF-8");
			} else {
				logger.error("get请求提交失败:" + url);
			}
		} catch (IOException e) {
			logger.error("get请求提交失败:" + url, e);
		} finally {
			try {
				httpClient.close();
			} catch (IOException e) {
			}
		}
		return jsonResult;
	}

	/**
	 * 创建SSL安全连接
	 *
	 * @return
	 */
	private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
		SSLConnectionSocketFactory sslsf = null;
		try {
			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

				public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
					return true;
				}
			}).build();
			sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {

				@Override
				public boolean verify(String arg0, SSLSession arg1) {
					return true;
				}

				@Override
				public void verify(String host, SSLSocket ssl) throws IOException {
				}

				@Override
				public void verify(String host, X509Certificate cert) throws SSLException {
				}

				@Override
				public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
				}
			});
		} catch (GeneralSecurityException e) {
			e.printStackTrace();
		}
		return sslsf;
	}

}